import json
import logging
import threading
from PySide6.QtCore import QThread, Signal
from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk
from osgeo import ogr
from osgeo.gdal import Driver
from osgeo.ogr import DataSource, Layer, Geometry, FeatureDefn, FieldDefn
# 驱动名称
from osgeo.osr import SpatialReference
import queue
import pandas as pd
import time


class DriverType:
    OPEN_FILE_GDB_DERIVE = "OpenFileGDB"
    ESRI_SHAPEFILE = "ESRI Shapefile"


if __name__ == '_main__':
    driver: Driver = ogr.GetDriverByName(DriverType.ESRI_SHAPEFILE)
    fileName = "F:\gis-data\QNZ_JSYDGZQ_4490.shp"
    dataSource: DataSource = driver.Open(fileName, 0)
    for index in range(dataSource.GetLayerCount()):
        layer: Layer = dataSource.GetLayerByIndex(index)
        for feature in layer:
            # 要素字段名集合
            keys = feature.keys()
            for key in keys:
                # 要素字段值
                value = feature.GetField(key)
                print("{}-->{}".format(key, value))
            # 图形字段
            geometry: Geometry = feature.geometry()
            m_area = (geometry.Area() / (0.0089 ** 2)) * 1e+6
            print(f"面积 ==={m_area}")
            print(geometry.ExportToJson())
            pass
            ##print(geometry)


def getDataSource(filePath=None, driverName=None) -> DataSource:
    driver: Driver = ogr.GetDriverByName(driverName)
    dataSource: DataSource = driver.Open(filePath)
    return dataSource


# 获取GDB图层
def getGdbLayer(gdbPath=None, driverType=None) -> []:
    if gdbPath is None:
        return
    if driverType is None:
        driverType = DriverType.ESRI_SHAPEFILE
    ds: DataSource = getDataSource(gdbPath, driverType)
    layerList = []
    for layerIndex in range(ds.GetLayerCount()):
        layer: Layer = ds.GetLayerByIndex(layerIndex)
        lay = {'index': layerIndex, 'name': layer.GetName()}
        layerList.append(lay)
    return layerList


def listGdbLayerPage(gdbPath=None, layerIndex=0, page=1, size=20, driverType=None):
    if driverType is None:
        driverType = DriverType.OPEN_FILE_GDB_DERIVE
    dataSource: DataSource = getDataSource(gdbPath, driverType)
    layer: Layer = dataSource.GetLayerByIndex(layerIndex)
    headers = []
    layerDefn: FeatureDefn = layer.GetLayerDefn()
    for fieldDefnIndex in range(layerDefn.GetFieldCount()):
        fieldDefn: FieldDefn = layerDefn.GetFieldDefn(fieldDefnIndex)
        headers.append(fieldDefn.GetName())

    gisData = []
    limit = 100
    currentIndex = 0

    for feature in layer:
        # 要素字段名集合
        rowData = []
        for key in headers:
            # 要素字段值
            value = feature.GetField(key)
            rowData.append(value)
        gisData.append(rowData)
        currentIndex += 1
        if limit < currentIndex:
            break
        # 图形字段
        # geometry: Geometry = feature.geometry()
        # m_area = (geometry.Area() / (0.0089 ** 2)) * 1e+6
        # print(f"面积 ==={m_area}")
        ##print(geometry)
    return headers, gisData, layer.GetFeatureCount()


class SendDataByThread(threading.Thread):
    def __init__(self, es, index, actions):
        threading.Thread.__init__(self)
        self.es = es
        self.index = index
        self.actions = actions

    def run(self):
        try:
            bulk(client=self.es, index=self.index, actions=self.actions)
        except BaseException as e:
            print("发布数据异常")


class PushingData2Es(QThread):
    progress = Signal(float)
    currentIndex = Signal(int)
    __count = 0
    __sum = 0

    def __init__(self, parent=None, path=None, layerIndex=None, host=None, username=None, password=None, esIndex=None,
                 driverType=None):
        super(PushingData2Es, self).__init__(parent)
        self.path = path
        self.layerIndex = layerIndex
        self.host = host
        self.username = username
        self.password = password
        self.esIndex = esIndex
        if driverType is None:
            driverType = DriverType.OPEN_FILE_GDB_DERIVE
        self.driverType = driverType

    def run(self):
        logging.info("发布数据")
        if self.username is None:
            __es = Elasticsearch(self.host)
        else:
            __es = Elasticsearch(
                [self.host],
                http_auth=(self.username, self.password)
            )
        listData = []
        for it in self.pushingData():
            listData.append(it)
            self.__sum += 1
            v = (self.__sum / self.__count) * 100
            self.progress.emit(v)
            self.currentIndex.emit(self.__sum)
            if len(listData) > 100:
                t = SendDataByThread(__es, self.esIndex, listData)
                t.start()
                listData.clear()
                # __es.index(index=self.esIndex, body=it)

    def pushingData(self):
        logging.info(str(f"pushingData    =  {self.path}"))
        if self.path is None:
            return
        if self.layerIndex is None:
            return
        __dataSource: DataSource = getDataSource(self.path, self.driverType)
        __layer: Layer = __dataSource.GetLayerByIndex(self.layerIndex)

        __layerSpatial: SpatialReference = __layer.GetSpatialRef()
        spatia4490: SpatialReference = SpatialReference()
        spatia4524: SpatialReference = SpatialReference()
        spatia4490.ImportFromEPSG(4490)
        spatia4524.ImportFromEPSG(4524)

        if not SpatialReference.IsSame(__layerSpatial, spatia4490):
            if SpatialReference.IsSame(__layerSpatial, spatia4524):
                pass
        headers = []
        layerDefn: FeatureDefn = __layer.GetLayerDefn()
        for fieldDefnIndex in range(layerDefn.GetFieldCount()):
            fieldDefn: FieldDefn = layerDefn.GetFieldDefn(fieldDefnIndex)
            headers.append(fieldDefn.GetName())
        self.__count = __layer.GetFeatureCount()
        for __feature in __layer:
            geom: Geometry = __feature.GetGeometryRef()
            if not geom.IsValid():
                geom = geom.MakeValid()
            itemData = {}
            if not geom is None:
                centroid: Geometry = geom.Centroid()
                itemData['central_point'] = [centroid.GetX(), centroid.GetY()]
                itemData['geom'] = json.loads(geom.ExportToJson())
                itemData['area'] = (geom.Area() / (0.0089 ** 2)) * 1e+6
                if not geom.IsValid():
                    del itemData['geom']

            for key in headers:
                # 要素字段值
                if key in ['Shape_Length', 'Shape_Area']:
                    continue
                value = __feature.GetField(key)
                if value is None:
                    continue
                itemData[key] = value
            yield itemData
